/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package analiseSintatica.Regras.Comandos;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.*;
import analiseSintatica.Regras.Declaracoes.RegraAtribuicaoVar;
import analiseSintatica.Regras.Expressoes.RegraExpressao;
import analiseSintatica.estruturadados.NoArvore;

import analiseSintatica.Regras.Expressoes.RegraAtribuicao;



import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Ivo Romário
 * 
 */
public class RegraFor extends Regra{
    
    protected String estrutura = "<for> ::= for ( <atribuicao> ; <expressao> ; (<atribuicao> | <expressao> ) ) <bloco>";

    RegraAtribuicaoVar atribuicao = RegraAtribuicaoVar.getInstance();
    RegraExpressao expressao = RegraExpressao.getInstance();
    RegraBloco bloco = RegraBloco.getInstance();

    protected static Regra instancia;




    /**
     * Construtor privado necessario ao singleton
     */
    private RegraFor() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraFor getInstance() {
        if (instancia == null) {
            instancia = new RegraFor();
        }
        return (RegraFor) instancia;
    }

   
    

    @Override
    public NoArvore analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {

        ErroSintaticoException erros = new ErroSintaticoException();
        
        NoArvore naoTerminalFor = new NoArvore("<for>", false);     //Cria-se um objeto NoArvore e adiciona-se a raiz dessa sub-arvore
                                                                    // que neste caso é o nao-terminal <for>, e o seu tipo (terminal ou nao-terminal).
        
        naoTerminalFor.adicionaFilho(reconhecerFor(listaTokens));   //Aqui é iniciada a construção da sub-árvore naoTerminalFor.

                    
        try{
            naoTerminalFor.adicionaFilho(reconheceLexema(listaTokens, "delimitador", "(",estrutura));
        }
        catch(ErroSintaticoException e){

        }
        try{
            naoTerminalFor.adicionaFilho(RegraAtribuicao.getInstance().analisar(listaTokens));
        }
        catch(ErroSintaticoException e){

        }

        try{
            naoTerminalFor.adicionaFilho(reconheceLexema(listaTokens, "delimitador", ";",estrutura));
        }
        catch(ErroSintaticoException e){

        }

        try{
            naoTerminalFor.adicionaFilho(RegraExpressao.getInstance().analisar(listaTokens));
        }
        catch(ErroSintaticoException e){

        }

        try{
            naoTerminalFor.adicionaFilho(reconheceLexema(listaTokens, "delimitador", ";",estrutura));
        }
        catch(ErroSintaticoException e){

        }

        try{
            if(atribuicao.getPrimeiro().contains(listaTokens.getFirst().getToken())){
                //Criarei uma sub-arvore de atribuicao.
                naoTerminalFor.adicionaFilho(RegraAtribuicao.getInstance().analisar(listaTokens));
            }
            else if(expressao.getPrimeiro().contains(listaTokens.getFirst().getToken())){
                //Criarei uma sub-arvore de expressao.
                naoTerminalFor.adicionaFilho(RegraExpressao.getInstance().analisar(listaTokens));
            }
        }
        catch(ErroSintaticoException e){

        }

        try{
            naoTerminalFor.adicionaFilho(reconheceLexema(listaTokens, "delimitador", ")",estrutura));
        }
        catch(ErroSintaticoException e){

        }

        try{
            naoTerminalFor.adicionaFilho(RegraBloco.getInstance().analisar(listaTokens));
        }
        catch(ErroSintaticoException e){

        }

        if(erros.size() != 0){
            throw erros;
        }

        return naoTerminalFor;
        
    }
     
    /**
     * Reconhece terminal "for"
     * @param listaTokens - Tokens do codigo
     * @return - Sub-arvore sintatica
     */
    public NoArvore reconhecerFor (LinkedList<LinkToken> listaTokens){
    
            listaTokens.removeFirst();
            return new NoArvore("for", true);
    }
    
    protected void setPrimeiro() {
        this.primeiro.add("for");
    }


    protected void setSeguinte() {
        seguinte = RegraCmd.getInstance().getSeguinte();
    }
    

}
